home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
cpp_libs
/
idioms.lha
/
idioms
/
5-11.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-08
|
5KB
|
209 lines
/* Copyright (c) 1992 by AT&T Bell Laboratories. */
/* Advanced C++ Programming Styles and Idioms */
/* James O. Coplien */
/* Fixed by Andy Piper - Cambridge University Engineering Department */
/* All rights reserved. */
#include <stddef.h>
#include <memory.h>
class LAPD {
friend class LAPDMemoryManager;
public:
void *operator new(size_t);
void operator delete(void *);
LAPD(char *const);
virtual ~LAPD() {}
protected:
LAPD() { /* no-op */ }
private:
int:8;
struct {
unsigned char flag;
unsigned int sapi:6;
unsigned int commandResponse:1;
unsigned int zero:1;
unsigned int tei:7;
unsigned int ext:1;
unsigned char control;
} header;
struct {
LAPD *linkf, *linkb;
unsigned short logSize;
} minfo;
protected:
union {
unsigned char tag; // minfo system allocated tag
size_t size;
};
void performCRCCheck() { /* . . . */ }
};
#define round(a,b) (((a+b-1)/b)*b)
class LAPDMemoryManager {
friend LAPD;
private:
enum { MessageBufSize=8192, Log2MessageBufSize=13 };
unsigned char availBuf[
(1+Log2MessageBufSize)*round(sizeof(LAPD),4)];
LAPD *avail;
unsigned char buf[MessageBufSize];
LAPD *buddy(int k, LAPD *l) {
unsigned char *cp = (unsigned char *) l;
return (LAPD*)(buf+(long(cp-buf) ^ (1<<k)));
}
public:
LAPDMemoryManager();
int savej;
LAPD *largestBlock();
void allocateResizeBlock(int ktemp);
void deallocateBlock(LAPD *l, int k);
};
LAPDMemoryManager::LAPDMemoryManager() {
LAPD* buf = (LAPD*)this->buf;
avail = (LAPD*)availBuf;
avail[Log2MessageBufSize].minfo.linkf =
avail[Log2MessageBufSize].minfo.linkb = buf;
buf[0].minfo.linkf = buf[0].minfo.linkb =
&avail[Log2MessageBufSize];
buf[0].tag = 1; /* unused */
buf[0].minfo.logSize = Log2MessageBufSize;
for (int k = 0; k < Log2MessageBufSize; k++) {
avail[k].minfo.linkf = avail[k].minfo.linkb =
(LAPD*)&avail[k];
}
}
LAPD * LAPDMemoryManager::largestBlock() {
for (int k = Log2MessageBufSize; k >= 0; --k) {
if (avail[k].minfo.linkf != &avail[k]) {
savej = k;
return avail[k].minfo.linkf;
}
}
return 0;
}
void LAPDMemoryManager::allocateResizeBlock(int ktemp) {
int k, j = savej;
// Round up to next 2**n
for (int i = 1; i < Log2MessageBufSize; i++) {
k = 1 << i;
if (k > ktemp) break;
}
LAPD *l = avail[j].minfo.linkf;
avail[j].minfo.linkf = l->minfo.linkf;
l->minfo.linkf->minfo.linkb = &avail[j];
for(l->tag = 0; j - i; ) {
--j;
LAPD *p = (LAPD*)(((char *)l) + (1 << j));
p->tag = 1;
p->minfo.logSize = j;
p->minfo.linkf = p->minfo.linkb = &avail[j];
avail[j].minfo.linkf = avail[j].minfo.linkb = p;
}
}
void LAPDMemoryManager::deallocateBlock(LAPD *l, int ktemp) {
int i;
for (int k = 0; k < Log2MessageBufSize; k++) {
i = 1 << k;
if (i >= ktemp) break;
}
for(;;) {
LAPD *p = buddy(k,l);
if (k==Log2MessageBufSize || p->tag == 0 || p->minfo.logSize != k) {
break;
}
p->minfo.linkb->minfo.linkf = p->minfo.linkf;
p->minfo.linkf->minfo.linkb = p->minfo.linkb;
++k;
if (p < l) l = p;
}
l->tag = 1;
l->minfo.linkf = avail[k].minfo.linkf;
avail[k].minfo.linkb = l;
l->minfo.logSize = k;
l->minfo.linkb = &avail[k];
avail[k].minfo.linkf = l;
}
static LAPDMemoryManager manager;
// this operator allows one object in the LAPD
// hierarchy to overlay itself with an instance
// of one of its derived classes
inline void *operator new(size_t, LAPD* l) { return l; }
class X25: public LAPD {
friend LAPD;
private:
struct X25PacketBody {
unsigned char rep[128];
};
~X25() { if (!size) size = sizeof(X25); }
X25(char *const m): LAPD() {
manager.allocateResizeBlock( sizeof(X25) );
::memcpy(&body, m, sizeof(body));
}
X25PacketBody body;
};
class EIN: public LAPD {
friend LAPD;
private:
struct EINPacketBody {
unsigned char rep[256];
};
~EIN() { if (!size) size = sizeof(EIN); }
EIN(char *const m): LAPD() {
manager.allocateResizeBlock( sizeof(EIN) );
::memcpy(&body, m, sizeof(body));
}
EINPacketBody body;
};
void *
LAPD::operator new(size_t /* unused */) {
return manager.largestBlock();
}
void
LAPD::operator delete(void *l) {
manager.deallocateBlock((LAPD*)l, ((LAPD*)l)->size);
}
LAPD::LAPD(char *const bits) {
::memcpy(&header, bits, sizeof(header));
performCRCCheck();
// Determine type of message based on address
switch(bits[0]) {
case 'a':
(void) ::new(this) X25(bits); break;
case 'b':
(void) ::new(this) EIN(bits); break;
default:
// error("invalid message"); break;
;
}
}
int main() {
LAPD *m, *n, *o, *p;
m = new LAPD("abcdefg");
n = new LAPD("badfljk;adsflkj;asldf");
delete n;
n = new LAPD("aadflkj;sadf");
o = new LAPD("aad;sflkj;lsdf");
p = new LAPD("bb");
delete p;
delete m;
delete n;
delete o;
}